package com.bitbakery.plugin.scheme.lang.lexer;

import com.bitbakery.plugin.scheme.lang.psi.SchemeElementType;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;

/**
 * Identifies all of the token types (at least, the ones we'll care about) in Common Lisp.
 * Used by the lexer to break a Lisp source file down into tokens.
 */
public interface SchemeTokenTypes {

    // Special characters
    IElementType LEFT_PAREN = new SchemeElementType("(");
    IElementType RIGHT_PAREN = new SchemeElementType(")");

    IElementType BACKQUOTE = new SchemeElementType("`");
    IElementType QUOTE = new SchemeElementType("'");
    IElementType COMMA = new SchemeElementType(",");
    IElementType COMMA_AT = new SchemeElementType(",@");
    IElementType SHARP_QUOTE = new SchemeElementType("#'");

    TokenSet SPECIAL_CHARACTERS = TokenSet.create(BACKQUOTE, QUOTE, COMMA, COMMA_AT, SHARP_QUOTE);


    // Keywords and special forms
    IElementType DEFINE = new SchemeElementType("define");
    IElementType DEFINE_SYNTAX = new SchemeElementType("define-syntax");
    IElementType SYNTAX_RULES = new SchemeElementType("syntax-rules");

    IElementType QUOTE_KEYWORD = new SchemeElementType("quote");
    IElementType LAMBDA = new SchemeElementType("lambda");
    IElementType COND = new SchemeElementType("cond");
    IElementType IF = new SchemeElementType("if");
    IElementType LET = new SchemeElementType("let");
    IElementType LET_STAR = new SchemeElementType("let*");
    IElementType LETREC = new SchemeElementType("letrec");
    IElementType SET = new SchemeElementType("set!");
    IElementType CONS = new SchemeElementType("cons");
    IElementType CAR = new SchemeElementType("car");
    IElementType CDR = new SchemeElementType("cdr");

    TokenSet KEYWORDS = TokenSet.create(QUOTE_KEYWORD, LAMBDA, COND, IF, LET, CONS, CAR, CDR);

    // Comments
    IElementType BLOCK_COMMENT = new SchemeElementType("block comment");
    IElementType LINE_COMMENT = new SchemeElementType("line comment");
    TokenSet COMMENTS = TokenSet.create(BLOCK_COMMENT, LINE_COMMENT);


    // Literals
    IElementType STRING_LITERAL = new SchemeElementType("string literal");
    IElementType NUMERIC_LITERAL = new SchemeElementType("numeric literal");

    IElementType TRUE = new SchemeElementType("t");
    IElementType FALSE = new SchemeElementType("f");
    IElementType NIL = new SchemeElementType("nil");
    TokenSet BOOLEAN_LITERAL = TokenSet.create(TRUE, NIL);

    TokenSet LITERALS = TokenSet.create(STRING_LITERAL, NUMERIC_LITERAL, TRUE, NIL);


    IElementType SYMBOL = new SchemeElementType("symbol");


    // Control characters
    IElementType EOL = new SchemeElementType("end of line");
    IElementType EOF = new SchemeElementType("end of file");
    IElementType WHITESPACE = TokenType.WHITE_SPACE;
    IElementType BAD_CHARACTER = TokenType.BAD_CHARACTER;

    TokenSet WHITESPACE_SET = TokenSet.create(EOL, EOF, WHITESPACE);
    // TODO - Should we distinguish between macros and functions that are destructive?
}